package org.jackysoft.service.impl;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.lucene.queryParser.ParseException;
import org.hibernate.Criteria;
import org.hibernate.Hibernate;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Restrictions;
import org.jackysoft.data.SortInfo;
import org.jackysoft.entity.AcegiRole;
import org.jackysoft.entity.Department;
import org.jackysoft.entity.Role;
import org.jackysoft.entity.User;
import org.jackysoft.entity.nosql.SecurityRoleNotify;
import org.jackysoft.service.AbstractIdentifiedService;
import org.jackysoft.service.UserService;
import org.jackysoft.util.OperationType;
import org.jackysoft.util.Page;
import org.jackysoft.util.SpringSecurityUtils;
import org.jackysoft.util.StringUtils;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.google.common.collect.Lists;

@Service
@Transactional
@SuppressWarnings("unchecked")
public class UserServiceImpl extends AbstractIdentifiedService<User>
		implements UserService {

	protected final Log log = LogFactory.getLog(UserServiceImpl.class);
	/**
	 * 
	 */
	private static final long serialVersionUID = 4040151041062681452L;

	public UserServiceImpl() {
		this.type = User.class;
	}
	
	
	@Override
	public User get(String id) throws DataAccessException {
			
		User user = (User) getSession().get(User.class, id);
		if (user != null) {
			Hibernate.initialize(user.getAuthoritys());
			Hibernate.initialize(user.getDepartment());
			Hibernate.initialize(user.getRole());
		}
		
		return user;
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRES_NEW, isolation = Isolation.SERIALIZABLE)
	public void remove(User user) throws DataAccessException {
		log.info("删除用户....");
		getSession().clear();
		super.remove(user);
		log.info("删除用户....[OK]");
	}

	@Override
	public Collection<User> searchs(String searchString)
			throws DataAccessException, ParseException {

		return null;
	}

	@Override
	public Collection<User> gets(final AcegiRole acegi)
			throws DataAccessException {
		Session sess = getSession();
		String hql = "from User u join a.authoritys auths where auth in(:auths)";
		Query q = sess.createQuery(hql).setParameterList("auths",
				new ArrayList<AcegiRole>() {
					{
						add(acegi);
					}
				});
		return q.list();
	}

	@Override
	public int getSize(SortInfo sortInfo, Map<String, Object> smap) {
		int size = 0;
		Query q = null;
		if (smap == null || smap.size() == 0)
			return super.getSize(sortInfo, smap);
		else if (smap.containsKey("authoritys")) {
			Collection<AcegiRole> auths = (Collection<AcegiRole>) smap
					.get("authoritys");
			String queryString = "select count(*) from User u join u.authoritys aus  where  aus in (:auths)";
			q = getSession().createQuery(queryString);
			q.setParameterList("auths", auths);

		} else {
			String hql = "select count(*) from User u where u.enabled=false";
			q = getSession().createQuery(hql);
		}
		Object o = q.uniqueResult();
		size = o == null ? 0 : Integer.parseInt(o.toString());
		return size;
	}

	@Override
	public Iterable<User> getData(int start, int size, boolean listAll,
			SortInfo sortInfo, Map<String, Object> smap) {
		if (smap == null)
			return super.getData(start, size, listAll, sortInfo, smap);
		else {
			Session sess = getSession();
			StringBuffer qs = new StringBuffer(
					"select new User(u.username,u.localName,u.department,u.role,u.enabled) from User u ");
			Query q = null;
			if (smap.keySet().contains("authoritys")) {
				Collection v = (Collection) smap.get("authoritys");
				qs.append(" left join u.authoritys aus where aus in (:auths)");
				q = sess.createQuery(qs.toString());
				q.setParameterList("auths", v);
			} else if (smap.keySet().contains("unpassed")) {
				qs.append(" where u.enabled=false");
				q = sess.createQuery(qs.toString());
			} else {
				q = sess.createQuery(qs.toString());
			}
			if (!listAll) {
				q.setFirstResult(start);
				q.setMaxResults(size);
			}
			List list = q.list();
			return list;
		}
	}

	@Override
	public Collection<User> getsBySameDepartment() throws DataAccessException {
		Session sess = getSession();
		User user = SpringSecurityUtils.getCurrentUser();
		Criteria crt = sess.createCriteria(User.class).add(
				Restrictions.eq("department", user.getDepartment()));
		return crt.list();
	}

	@Override
	public void saveProfile(User user) throws DataAccessException {

		String username = SpringSecurityUtils.getCurrentUserName();
		if (StringUtils.isEmpty(user.getPassword())) {
			user.setPassword("12345678");
		}

		User tu = get(username);
		tu.setRepassword(user.getRepassword());
		tu.setDepartment(user.getDepartment());
		tu.setPassword(user.getPassword());

	}

	@Override
	public Page gets(Department dept, int start, int size)
			throws DataAccessException {
		Session session = getSession();
		String hql = "select count(*) from " + this.table() + " u ";
		String where = " where u.department=? or u.department.topParent=?";
		Object o = session.createQuery(hql + where).setParameter(0, dept)
				.setParameter(1, dept).uniqueResult();

		int total = o == null ? 0 : Integer.decode(o + "");
		Page page = new Page();

		hql = "from " + this.table() + " u ";
		Query q = session.createQuery(hql + where).setParameter(0, dept)
				.setParameter(1, dept).setFirstResult((start - 1) * size)
				.setMaxResults(size);
		List list = q.list();		
		page.setRecords(total);
		page.setRows(list);
		page.setPage(start);
		return page;
	}

	@Override
	public Page gets(Role role, int start, int size) throws DataAccessException {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Collection<User> gets(Department dept) throws DataAccessException {
		Session session = getSession();
		Criteria crt = session.createCriteria(User.class);
		crt.add(Restrictions.eq("department", dept));
		List list = crt.list();
		Collections.sort(list);
		return list;
	}

	@Override
	public Collection<User> gets(Role dept) throws DataAccessException {
		Session session = getSession();
		Criteria crt = session.createCriteria(User.class);
		crt.add(Restrictions.eq("role", dept));
		List list = crt.list();
		return list;
	}

	@Override
	public Collection<User> gets(Collection<Department> depts)
			throws DataAccessException {
		if (depts == null || depts.size() == 0)
			return Lists.newArrayList();
		Session session = getSession();
		Criteria crt = session.createCriteria(this.type);
		crt.add(Restrictions.in("department", depts));
		return crt.list();
	}

	@Override
	public Collection<User> getsByRoles(Collection<Role> roles)
			throws DataAccessException {
		if (roles == null || roles.size() == 0)
			return Lists.newArrayList();
		Session session = getSession();
		Criteria crt = session.createCriteria(this.type);
		crt.add(Restrictions.in("role", roles));
		return crt.list();
	}

	@Override
	public void reset(Department dept) throws DataAccessException {
		Session session = getSession();
		session.createQuery(
				"update " + this.table()
						+ " u set u.department=null where u.department=:dept")
				.setParameter("dept", dept).executeUpdate();
	}

	@Override
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = true)
	public User getByLogin(Serializable id) throws DataAccessException {
		User fuser = get((String) id);
		
		User luser = new User();
		try {
			if(fuser==null){
				throw new InstantiationException("User not found with name:"+id);
				
			}
			BeanUtils.copyProperties(luser, fuser);
		} catch (IllegalAccessException e) {
			log.error(e);
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			log.error(e);
			e.printStackTrace();
		} catch (InstantiationException e) {
			log.error(e.getMessage());
			//e.printStackTrace();
		}
		Department dept = luser.getDepartment();
		if (dept == null)
			return luser;
		List<String> names = Lists.newArrayList();
		String deptId = dept.getId();
		
		while (dept != null) {
			names.add(dept.getName());
			if (dept.getParent() != null) {
				dept = dept.getParent();
				deptId = dept.getId();
			} else {
				break;
			}
		}
		String name = "";
	    for(int i=names.size()-1;i>=0;i--){
	    	name+=names.get(i)+" ";
	    }
		dept.setId(deptId);
		dept.setName(name);
		luser.setDepartment(dept);
		return luser;
	}

	@Override
	public void pass(Collection<User> beans) throws DataAccessException {
		if (beans == null || 0 == beans.size())
			return;
		for (User u : beans) {
			User tu = get(u.getUsername());
			tu.setRepassword(tu.getPassword());
			tu.setEnabled(true);
			getSession().update(tu);
		}
	}

	@Override
	public boolean exists(String username) throws DataAccessException {
		return get(username) != null;
	}

	@Override
	public void create(User b) throws DataAccessException {
		SecurityRoleNotify notify = new SecurityRoleNotify(b.getUsername()
				+ "[" + b.getLocalName() + "需要审核]", new Date(),
				OperationType.Create);
		notifyService.create(notify);
		b.setEnabled(true);
		super.create(b);
	}

	@Override
	public void update(User b) throws DataAccessException {
		SecurityRoleNotify notify = new SecurityRoleNotify(b.getUsername()
				+ "[" + b.getLocalName() + "需要审核]", new Date(),
				OperationType.Update);
		notifyService.create(notify);
		b.setEnabled(true);
		super.update(b);
	}

	@Override
	public void marked4Remove(User owner) throws DataAccessException {
		User user = get(owner.getUsername());
		if (user != null)
			user.setRemoved(true);
		
	    

	}
	
	
	

}
